/*
 *  MandelbrotSet.cpp
 *  mandelbrot
 *
 *  Created by Filip Krikava on 3/3/10.
 *  Copyright 2010 __MyCompanyName__. All rights reserved.
 *
 */

#include "MandelbrotSet.h"

#include <boost/format.hpp>
#include <math.h>

image_t* MandelbrotSet::render(const RenderingOptions& options) {

	image_t* image = new image_t;
	image->width = options.width;
	image->height = options.height;
	image->data = new rgb_t *[options.height];

	double zx, zy, zx2, zy2;
	double cx, cy;
	double cx0, cy0;

	cy0 = options.ymin;

	// for all rows in the image
	for (int y = 0; y < options.height; y++) {
		cx0 = options.xmin;
		// this get's the pointer for the exact line in the image which can be directly accessed to set a color. It's like big array of colors
		image->data[y] = new rgb_t[options.width];
		rgb_t *scanLine = image->data[y];
		// for each pixel in a row
		for (int x = 0; x < options.width; x++) {
			// now we start computing the point whether it's a part of the set
			cx = cx0;
			cy = cy0;
			zx = zy = 0.0;
			int i;

			for (i = 0; i < options.max_iterations; i++) {

				// z^2
				zx2 = zx * zx;
				zy2 = zy * zy;

				// check divergation
				if (zx2 + zy2 > 4.0)
					break;
				// z(n+1)
				zy = 2.0 * zx * zy + cy;
				zx = zx2 - zy2 + cx;
			}

			// draw computed pixel pixel
			rgb_t rgb;
			if (i != options.max_iterations) {
				rgb = computeColor(i, zx, zy);
			} else {
				rgb = COLOR_BLACK;
			}

			*scanLine++ = rgb;

			// new point int a line
			cx0 += (options.xmax - options.xmin) / options.width;
		}
		// new line
		cy0 += (options.ymax - options.ymin) / options.height;
	}

	return image;
}

std::string RenderingOptions::toString() {
	std::string s;
	s = str(boost::format("dimenstions: [%dx%d] plane: [%f,%f; %f,%f] max iterations: %d") % width % height % xmin % ymin % xmax % ymax % max_iterations);
	return s;
}

rgb_t computeColor(int iter, double zx, double zy) {
	double d = iter + 1 - (log(log(sqrt(zx * zx + zy * zy)))) / log(2);
	//double d = iter;

	int r = (int) 127 + 127.0 * sin(d / 30.0);
	int g = (int) d * 20.0;
	int b = (int) 127 - 127.0 * sin(d / 30.0);

	return rgb(r, g, b);
}

